package com.njust.RateMyTray_backend.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.njust.RateMyTray_backend.common.ResourceNotFoundException;
import com.njust.RateMyTray_backend.dto.MerchantWindowUpdateDTO;
import com.njust.RateMyTray_backend.dto.WindowQueryDTO;
import com.njust.RateMyTray_backend.entity.Comment;
import com.njust.RateMyTray_backend.entity.Dish;
import com.njust.RateMyTray_backend.entity.User;
import com.njust.RateMyTray_backend.entity.Window;
import com.njust.RateMyTray_backend.mapper.WindowMapper;
import com.njust.RateMyTray_backend.service.CommentService;
import com.njust.RateMyTray_backend.service.DishService;
import com.njust.RateMyTray_backend.service.UserService;
import com.njust.RateMyTray_backend.service.WindowService;
import com.njust.RateMyTray_backend.vo.CommentVO;
import com.njust.RateMyTray_backend.vo.DishVO;
import com.njust.RateMyTray_backend.vo.WindowDetailVO;
import com.njust.RateMyTray_backend.vo.WindowItemVO;
import com.njust.RateMyTray_backend.vo.WindowListVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import com.njust.RateMyTray_backend.common.ForbiddenException;

@Slf4j
@Service
public class WindowServiceImpl extends ServiceImpl<WindowMapper, Window> implements WindowService {

    private final ObjectMapper objectMapper = new ObjectMapper();

    @Lazy // 添加 @Lazy 注解来打破循环依赖
    @Autowired
    private DishService dishService;

    @Lazy // 再次添加 @Lazy 注解来打破三方循环依赖
    @Autowired
    private CommentService commentService;

    @Autowired
    private UserService userService;

    @Override
    public WindowListVO getWindowList(WindowQueryDTO queryDTO) {
        Page<Window> page = new Page<>(queryDTO.getPage(), queryDTO.getSize());

        // 排序逻辑
        if (StringUtils.hasText(queryDTO.getSortBy())) {
            String sortBy = queryDTO.getSortBy();
            boolean isAsc = "asc".equalsIgnoreCase(queryDTO.getOrder());
            String sortColumn = null;

            if ("popularity".equals(sortBy)) {
                sortColumn = "rating_count";
            } else if ("rating".equals(sortBy)) {
                sortColumn = "average_rating";
            }
            
            if(sortColumn != null) {
                if (isAsc) {
                    page.addOrder(OrderItem.asc(sortColumn));
                } else {
                    page.addOrder(OrderItem.desc(sortColumn));
                }
            }
        }

        // 查询逻辑
        LambdaQueryWrapper<Window> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.hasText(queryDTO.getName()), Window::getWindowName, queryDTO.getName());
        queryWrapper.eq(StringUtils.hasText(queryDTO.getStatus()), Window::getStatus, queryDTO.getStatus());
        // location 筛选
        if (StringUtils.hasText(queryDTO.getLocation())) {
            // 这里简单实现，假设 location 参数是食堂名称
            queryWrapper.like(Window::getCanteenName, queryDTO.getLocation());
        }

        this.page(page, queryWrapper);

        // 数据转换
        List<WindowItemVO> windowItems = page.getRecords().stream()
                .map(this::convertWindowToVO)
                .collect(Collectors.toList());

        return WindowListVO.builder()
                .total(page.getTotal())
                .pages(page.getPages())
                .currentPage(page.getCurrent())
                .windows(windowItems)
                .build();
    }

    @Override
    public WindowDetailVO getWindowDetails(Long windowId) {
        // 1. 获取窗口信息
        Window window = this.getById(windowId);
        if (window == null) {
            throw new ResourceNotFoundException("窗口不存在");
        }

        // 2. 获取菜品列表
        LambdaQueryWrapper<Dish> dishQuery = new LambdaQueryWrapper<>();
        dishQuery.eq(Dish::getWindowId, windowId);
        List<Dish> dishes = dishService.list(dishQuery);
        List<DishVO> dishVOs = dishes.stream().map(dish -> DishVO.builder()
                .dishId(dish.getId())
                .name(dish.getDishName())
                .price(dish.getPrice())
                .imageUrl(dish.getImageUrl())
                .description(dish.getDescription())
                .status(dish.getStatus())
                .build()).collect(Collectors.toList());
        
        // 3. 获取最新10条评论
        LambdaQueryWrapper<Comment> commentQuery = new LambdaQueryWrapper<>();
        commentQuery.eq(Comment::getTargetId, windowId)
                     .eq(Comment::getTargetType, "window")
                     .orderByDesc(Comment::getCommentedAt)
                     .last("LIMIT 10");
        List<Comment> comments = commentService.list(commentQuery);

        // 4. 获取评论关联的用户信息
        List<Long> userIds = comments.stream().map(Comment::getReviewerId).distinct().collect(Collectors.toList());
        Map<Long, User> userMap = userIds.isEmpty() ? Collections.emptyMap() :
                userService.listByIds(userIds).stream().collect(Collectors.toMap(User::getId, user -> user));

        // 5. 转换评论为VO
        List<CommentVO> commentVOs = comments.stream().map(comment -> {
            User reviewer = userMap.get(comment.getReviewerId());
            CommentVO vo = new CommentVO();
            vo.setCommentId(comment.getId());
            vo.setParentId(comment.getParentId());
            vo.setRating(comment.getRating());
            vo.setContent(comment.getContent());
            vo.setCommentTime(comment.getCommentedAt());
            vo.setHelpfulCount(comment.getHelpfulCount());
            vo.setIsOfficialReply(comment.getIsOfficialReply());
            vo.setImageUrls(parseImageUrls(comment.getImageUrls()));

            if (comment.getIsAnonymous()) {
                vo.setReviewerName("匿名用户");
                vo.setAvatarUrl(null); // 或者是一个默认的匿名头像URL
            } else if (reviewer != null) {
                vo.setReviewerName(reviewer.getNickname());
                vo.setAvatarUrl(reviewer.getAvatarUrl());
            }
            return vo;
        }).collect(Collectors.toList());
        
        // 6. 组装完整的WindowDetailVO
        return WindowDetailVO.builder()
                .windowId(window.getId())
                .windowName(window.getWindowName())
                .description(window.getDescription())
                .canteenName(window.getCanteenName())
                .floor(window.getFloor())
                .phoneNumber(window.getPhoneNumber())
                .businessHours(window.getBusinessHours())
                .coverImageUrl(window.getCoverImageUrl())
                .announcement(window.getAnnouncement())
                .status(window.getStatus())
                .merchantId(window.getMerchantId())
                .averageRating(window.getAverageRating())
                .ratingCount(window.getRatingCount())
                .dishes(dishVOs)
                .comments(commentVOs)
                .build();
    }

    @Override
    public void updateWindowByMerchant(Long windowId, Long merchantUserId, MerchantWindowUpdateDTO updateDTO) {
        Window window = this.getById(windowId);
        if (window == null) {
            throw new ResourceNotFoundException("窗口不存在");
        }
        
        // 权限验证：确保操作者是窗口的所有者
        if (!window.getMerchantId().equals(merchantUserId)) {
            throw new ForbiddenException("无权限操作此窗口");
        }

        // 动态更新字段
        if (StringUtils.hasText(updateDTO.getName())) window.setWindowName(updateDTO.getName());
        if (StringUtils.hasText(updateDTO.getDescription())) window.setDescription(updateDTO.getDescription());
        if (StringUtils.hasText(updateDTO.getCanteenName())) window.setCanteenName(updateDTO.getCanteenName());
        if (updateDTO.getFloor() != null) window.setFloor(updateDTO.getFloor());
        if (StringUtils.hasText(updateDTO.getPhoneNumber())) window.setPhoneNumber(updateDTO.getPhoneNumber());
        if (updateDTO.getPricePerPerson() != null) window.setPricePerPerson(updateDTO.getPricePerPerson());
        if (StringUtils.hasText(updateDTO.getOperatingHours())) window.setBusinessHours(updateDTO.getOperatingHours());
        if (StringUtils.hasText(updateDTO.getCoverImageUrl())) window.setCoverImageUrl(updateDTO.getCoverImageUrl());
        if (StringUtils.hasText(updateDTO.getAnnouncement())) window.setAnnouncement(updateDTO.getAnnouncement());
        if (StringUtils.hasText(updateDTO.getStatus())) window.setStatus(updateDTO.getStatus());
        
        window.setUpdatedAt(LocalDateTime.now());
        this.updateById(window);
    }

    @Override
    public WindowDetailVO getMerchantFirstWindow(Long merchantId) {
        // 1. 查找商家管理的第一个窗口
        LambdaQueryWrapper<Window> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Window::getMerchantId, merchantId)
                    .orderByAsc(Window::getId) // 按ID排序，获取第一个创建的窗口
                    .last("LIMIT 1");
        
        Window window = this.getOne(queryWrapper);
        if (window == null) {
            throw new ResourceNotFoundException("当前商家没有管理任何窗口");
        }
        
        // 2. 使用已有的getWindowDetails方法获取完整信息
        return getWindowDetails(window.getId());
    }

    private WindowItemVO convertWindowToVO(Window window) {
        String location = window.getCanteenName() + " " + window.getFloor() + "楼";
        String operatingHours = formatBusinessHours(window.getBusinessHours());
        
        return WindowItemVO.builder()
                .windowId(window.getId())
                .name(window.getWindowName())
                .location(location)
                .operatingHours(operatingHours)
                .status(window.getStatus())
                .averageRating(window.getAverageRating())
                .ratingCount(window.getRatingCount())
                .coverImageUrl(window.getCoverImageUrl())
                .build();
    }
    
    private List<String> parseImageUrls(String json) {
        if (!StringUtils.hasText(json)) {
            return Collections.emptyList();
        }
        try {
            return objectMapper.readValue(json, new TypeReference<List<String>>() {});
        } catch (JsonProcessingException e) {
            log.error("解析图片URL列表JSON失败: {}", json, e);
            return Collections.emptyList();
        }
    }

    private String formatBusinessHours(String jsonHours) {
        if (!StringUtils.hasText(jsonHours)) {
            return "暂无营业时间信息";
        }
        try {
            // 假设JSON格式为 {"weekday": "08:00-20:00", "weekend": "09:00-21:00"}
            Map<String, String> hoursMap = objectMapper.readValue(jsonHours, Map.class);
            // 这里简单返回第一个找到的时间段，可以根据业务需求做得更复杂
            return hoursMap.values().stream().findFirst().orElse("时间信息错误");
        } catch (JsonProcessingException e) {
            log.error("解析营业时间JSON失败: {}", jsonHours, e);
            // 如果JSON解析失败，直接返回原始字符串
            return jsonHours;
        }
    }
} 